package br.com.srv.componentes.relatorio.controleextensao.service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import br.com.srv.commons.service.impl.BasicServiceImpl;
import br.com.srv.componentes.cerca.util.PontosTOComparator;
import br.com.srv.componentes.cerca.util.PontosTODataComparator;
import br.com.srv.componentes.cerca.util.VeiculoTOComparator;
import br.com.srv.componentes.jdbcdao.DadosLidoJdbcDAO;
import br.com.srv.componentes.relatorio.velocidademedia.util.GeometriaAnalitica;
import br.com.srv.componentes.rota.service.RotaService;
import br.com.srv.model.ControleExtensaoTO;
import br.com.srv.model.PontoTO;
import br.com.srv.model.RotaTO;
import br.com.srv.model.VeiculoTO;
import br.com.srv.util.DateHelper;

public class ControleExtensaoServiceImpl
	extends BasicServiceImpl implements ControleExtensaoService {

	private RotaService rotaService;	
	DadosLidoJdbcDAO dadosLidoJdbcDAO;
	
	public List<Map> consultaControleExtensao(ControleExtensaoTO controleExtensaoTO) throws Exception {

		 List<Map> resultado = new ArrayList<Map>();
		 
		 GeometriaAnalitica geometriaAnalitica = new GeometriaAnalitica();
		
		//Pegar a rota
		List<RotaTO> rotas = new ArrayList<RotaTO>();
		if (controleExtensaoTO.getRotaId() == null
				|| controleExtensaoTO.getRotaId().equals("")) {	
			RotaTO rotaTO = new RotaTO();
			rotaTO.setClienteId(controleExtensaoTO.getClienteId());
			rotas.addAll(getRotaService().buscarRotas(rotaTO));
		} else {
			rotas.add((RotaTO)getBasicDAO().findById(
					RotaTO.class, new Integer(controleExtensaoTO.getRotaId())));
		}
		
		for (RotaTO rotaTO : rotas) {

			List<PontoTO> pontosRota = new ArrayList<PontoTO>();
			
			//ordena pontos da rota por data
			pontosRota.addAll(rotaTO.getPontosFiscalizacao());
			Collections.sort(pontosRota, new PontosTOComparator());				
			
			//pegar ponto inicial da rota
			PontoTO pontoInicio = pontosRota.get(0);
			
			//pegar ponto final da rota
			PontoTO pontoFim = pontosRota.get(pontosRota.size() - 1);
			
			//ordena veiculos por descricao
			List<VeiculoTO> veiculos = new ArrayList<VeiculoTO>();
			
			if (controleExtensaoTO.getVeiculoId() == null || controleExtensaoTO.getVeiculoId().equals("")) {
				veiculos.addAll(rotaTO.getVeiculos());
				Collections.sort(veiculos, new VeiculoTOComparator());
			} else {
				veiculos.add((VeiculoTO)getBasicDAO().findById(
						VeiculoTO.class, new Integer(controleExtensaoTO.getVeiculoId())));
			}
			
			for (VeiculoTO veiculoTO : veiculos) {
				
				List<ControleExtensaoTO> lista = new ArrayList<ControleExtensaoTO>();

				//passar data para formato aceito no DB.
				String dataInicial = DateHelper.parseStringDateToStringDateJdbc(
						controleExtensaoTO.getPeriodoTO().getDataInicial());
				String dataFinal = DateHelper.parseStringDateToStringDateJdbc(
						controleExtensaoTO.getPeriodoTO().getDataFinal());
				
				List<Map<String, String>> dados = getDadosLidoJdbcDAO().consultaPontosByVeiculo(
						veiculoTO.getRealId().toString(), dataInicial, dataFinal,
						controleExtensaoTO.getPeriodoTO().getHoraInicial(),
						controleExtensaoTO.getPeriodoTO().getHoraFinal());
				
				List<PontoTO> pontosVeiculo = gerarListaPontoTOs(dados);
				
				//ordena pontos do veiculo por data
				Collections.sort(pontosVeiculo, new PontosTODataComparator());
				
				boolean flagInicio = false;
				double distanciaPercorrida = 0;
				double somatorioDistanciaPercorrida = 0;
				
				ControleExtensaoTO controleExtensaoTO2 = new ControleExtensaoTO();
				
				for (PontoTO pontoVeiculo : pontosVeiculo) {
					
					
					
					if (!flagInicio && geometriaAnalitica.distanciaEntrePontos(pontoVeiculo, pontoInicio)
							<= GeometriaAnalitica.PERTO) {
						flagInicio = true;				
						controleExtensaoTO2 = new ControleExtensaoTO();
						controleExtensaoTO2.getPeriodoTO().setDataInicial(pontoVeiculo.getDataHora());
						controleExtensaoTO2.setDescricaoVeiculo(veiculoTO.getDescricao());
					} else if (flagInicio && geometriaAnalitica.distanciaEntrePontos(pontoVeiculo, pontoFim)
							<= GeometriaAnalitica.PERTO) {					
						distanciaPercorrida += pontoVeiculo.getDistanciaUltimoPonto();
						controleExtensaoTO2.getPeriodoTO().setDataFinal(pontoVeiculo.getDataHora());
						controleExtensaoTO2.setDistanciaPercorrida(""+distanciaPercorrida);
						
						//acumular dist�ncia percorrida
						somatorioDistanciaPercorrida += distanciaPercorrida;
						
						//reinicializar contadores
						flagInicio = false;					
						distanciaPercorrida = 0;
						
						
						lista.add(controleExtensaoTO2);
						
					} else if (flagInicio){
						distanciaPercorrida += pontoVeiculo.getDistanciaUltimoPonto();
					}
					
				}
				
				if (flagInicio) {
					controleExtensaoTO2.getPeriodoTO().setDataFinal("-");
					controleExtensaoTO2.setDistanciaPercorrida(""+distanciaPercorrida);		
					
					//acumular disti�ncia percorrida
					somatorioDistanciaPercorrida += distanciaPercorrida;
					
	//				reinicializar contadores
					flagInicio = false;
					distanciaPercorrida = 0;				
					lista.add(controleExtensaoTO2);				
				}			
								
				
				Map<String, Object> mapa = new HashMap<String, Object>();
				mapa.put("lista", lista);
				mapa.put("consolidado", somatorioDistanciaPercorrida);
				resultado.add(mapa);
			
			}
		}
		
		return resultado;
	}

	public RotaService getRotaService() {
		return rotaService;
	}

	public void setRotaService(RotaService rotaService) {
		this.rotaService = rotaService;
	}

	public DadosLidoJdbcDAO getDadosLidoJdbcDAO() {
		return dadosLidoJdbcDAO;
	}

	public void setDadosLidoJdbcDAO(DadosLidoJdbcDAO dadosLidoJdbcDAO) {
		this.dadosLidoJdbcDAO = dadosLidoJdbcDAO;
	}		
	
	private List<PontoTO> gerarListaPontoTOs(List<Map<String, String>> pontos) {
		List<PontoTO> pontosVeiculo = new ArrayList<PontoTO>();
		for (Map mapa : pontos) {
			PontoTO pontoTO = new PontoTO();
			pontoTO.setDataHora((String)mapa.get("DATE_TIME"));
			pontoTO.setLongitude(new Double((String)mapa.get("X")));
			pontoTO.setLatitude(new Double((String)mapa.get("Y")));	
			pontoTO.setVelocidade(new Double((String)mapa.get("VEL")));	
			pontoTO.setDistanciaUltimoPonto(new Double((String)mapa.get("DIST_BETWEEN_POSITIONS")));
			pontoTO.setDescricao((String)mapa.get("NEAR_DESC"));
			pontosVeiculo.add(pontoTO);
		}
		return pontosVeiculo;
	}
	
}
